/**
* @file drv_i2c.c
* @brief  i2c driver
* @details 
* @author huangbin
* @version V1.0.0
* @date 2025-05-10
* @copyright All documents are copyrighted by Shenzhen Xinlongwei Technology Co., LTD.
*            They may not be used for commercial purposes without permission
*/
#include "inc.h"

static void I2cSdaSetInput(void)
{
	GPIO_InitTypeDef GPIO_InitStructure;
    
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_InitStructure.GPIO_Mode =  GPIO_Mode_IPD;

	GPIO_InitStructure.GPIO_Pin = I2C_SDA_PIN;
	GPIO_Init (I2C_SDA_PORT, & GPIO_InitStructure );
}
static void I2cSdaSetOuput(void)
{
	GPIO_InitTypeDef GPIO_InitStructure;
    
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_InitStructure.GPIO_Mode =  GPIO_Mode_Out_PP;

	GPIO_InitStructure.GPIO_Pin = I2C_SDA_PIN;
	GPIO_Init (I2C_SDA_PORT, & GPIO_InitStructure );
}
static void I2cDelay(void)
{
//	volatile uint32_t i;
//	for(i = 0;i < 20;i++) __NOP(); //数据错误：20=500K@-O1,216Mhz
//	for(i = 0;i < 30;i++) __NOP(); //ok：30=350K@-O1,216Mhz
//    for(i = 0;i < 40;i++) __NOP();
//    HardWareDelay_us(10); //50K
    HardWareDelay_us(4); //2us读有信息错误，坐标ok
}

void I2c_Init(void)
{
	GPIO_InitTypeDef GPIO_InitStructure;

	RCC_APB2PeriphClockCmd (I2C_SDA_PORT_CLK|I2C_CLK_PORT_CLK,ENABLE);

	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_InitStructure.GPIO_Mode =  GPIO_Mode_Out_PP;

	GPIO_InitStructure.GPIO_Pin = I2C_SDA_PIN;
	GPIO_Init (I2C_SDA_PORT, & GPIO_InitStructure );
	
	GPIO_InitStructure.GPIO_Pin = I2C_CLK_PIN;
	GPIO_Init (I2C_CLK_PORT, & GPIO_InitStructure );

	I2C_SDA_HIGH();
	I2C_CLK_HIGH();
}
static uint16_t I2cGetSda(void)
{
    uint16_t portSda;
    portSda = I2C_SDA_PORT->IDR;
	if(portSda & I2C_SDA_PIN)
		return 1;
	return 0;
}
	
static I2C_ACK_STATUS I2cWaitAck(void)
{
	I2C_ACK_STATUS ack;
	
	I2cSdaSetInput();
	I2cDelay();
	I2C_CLK_HIGH();
	I2cDelay();
	ack = (I2C_ACK_STATUS)I2cGetSda();
	I2C_CLK_LOW();
	I2cDelay();
	I2cSdaSetOuput();
	return ack;
}
static void I2c_Ack( void )
{
	I2C_CLK_LOW();
	I2cDelay();
	I2cSdaSetOuput();
	I2C_SDA_LOW(); //0
	I2cDelay();
	I2C_CLK_HIGH();
	I2cDelay();
	I2C_CLK_LOW();
	I2cDelay();
}
static void I2c_Nack( void )
{
	I2C_CLK_LOW();
	I2cDelay();
	I2cSdaSetOuput();
	I2C_SDA_HIGH(); //1
	I2cDelay();
	I2C_CLK_HIGH();
	I2cDelay();
	I2C_CLK_LOW();
	I2cDelay();
}
//////////////////////////////////////////////////////////////////////
void I2c_Start(void)
{          
	I2C_CLK_HIGH();
	I2cDelay();
	
	I2C_SDA_HIGH();
	I2cDelay();	
	
	I2C_SDA_LOW();
	I2cDelay();	
	
	I2C_CLK_LOW();
	I2cDelay();	
}
void I2c_Stop(void)
{
	I2C_CLK_LOW();
	I2C_SDA_LOW();
	I2cDelay();
                   
	I2C_CLK_HIGH();
	I2cDelay();
	I2C_SDA_HIGH();
	I2cDelay();	
}
I2C_ACK_STATUS I2c_WriteByte(uint8_t byte)
{
	int i;
	
	// send byte
	for ( i = 0; i < 8; i++ )
	{
		I2C_CLK_LOW();
		if ( byte & 0x80 )
			I2C_SDA_HIGH();
		else
			I2C_SDA_LOW();
		I2cDelay();
		I2C_CLK_HIGH();
		I2cDelay();
		byte <<= 1;
	}
	// get ack                          
	I2C_CLK_LOW();
	I2cDelay();
	return I2cWaitAck();
}
uint8_t I2c_ReadByte(I2C_ACK_STATUS ack)
{
	uint8_t byte = 0;
	int i;
	
	I2cSdaSetInput();
    I2cDelay();
	for ( i = 0; i < 8; i++ )
	{
		byte <<= 0x1;
		// clk lower
		I2C_CLK_LOW();
		I2cDelay();
		
		// clk hight
		I2C_CLK_HIGH();
		I2cDelay();
		if ( I2cGetSda() ){
			byte |= 0x1;
		}else{
			byte &= ~0x1;
		}
	}
	if(ack == I2C_ACK)
		I2c_Ack();
	else
		I2c_Nack();
	return byte;
}
//////////////////////////////////////////////////////////



